(function($) {
	// private functions
	function mergeOptions(needTooltipID) {
		var map = $.fn.tooltip.map;
		var options = map[needTooltipID];
		var defaults = $.fn.tooltip.defaults;
		options = $.extend({},defaults,options || {});
		options.speechBubbleArrowClass = options.speechBubbleGeneralCSSClass + '_' + options.position;
		return options;
	}
	function debug($obj) {
		if (window.console && window.console.log) {
			window.console.log('hilight selection count: ' + $obj.size());
		}
	}
	function show(dom) {
		var mandatoryDistance = 8; // If the speech bubble is being used, and it is too close to the need_tooltip element, you cannot click on the element
		var needTooltipID = dom.attr('id');
		var options = mergeOptions(needTooltipID);
		var needTooltip_offsetParent = dom.offsetParent();
		needTooltip_offsetParent = $('body');
		var tooltip;
		if (options.content) {
		} else {
			var tooltipID = needTooltipID + '_tooltip';
			tooltip = $('#' + tooltipID);
			//tooltip.remove();
			//tooltip.hide();
			needTooltip_offsetParent.append(tooltip);
		}
		// Determines the position for the tooltip
		tooltip.addClass(options.cssClass); // We need to add this class here so that margin, padding, and border are taken into our calculation
		var needTooltip_position = dom.offset();
		var needTooltip_top = Math.floor(needTooltip_position['top']);
		var needTooltip_left = Math.floor(needTooltip_position['left']);
		var needTooltip_width = dom.outerWidth();
		var needTooltip_height = dom.outerHeight();
		var needTooltip_right = needTooltip_left + needTooltip_width;
		var needTooltip_bottom = needTooltip_top + needTooltip_height;
		var tooltip_top, tooltip_left;
		if (options.position == 'right') {
			tooltip_left = needTooltip_right + options.speechBubbleHeight + mandatoryDistance;
			if (options.verticalAlignment == 'top') {
				tooltip_top = needTooltip_top;
			} else if (options.verticalAlignment == 'bottom') {
				tooltip_top = needTooltip_bottom - tooltip.outerHeight();
			} else if ((options.verticalAlignment == 'middle') || (options.verticalAlignment == 'center')) {
				var needTooltip_verticalCenter = needTooltip_top + Math.floor(dom.outerHeight() / 2);
				var tooltip_height = tooltip.outerHeight();
				var tooltip_top = needTooltip_verticalCenter - Math.floor(tooltip_height / 2);
			} else {
				tooltip_top = needTooltip_top + parseInt(options.verticalAlignment);
			}
		} else if (options.position == 'left') {
			tooltip_left = needTooltip_left - options.speechBubbleHeight - tooltip.outerWidth() - mandatoryDistance;
			if (options.verticalAlignment == 'top') {
				tooltip_top = needTooltip_top;
			} else if (options.verticalAlignment == 'bottom') {
				tooltip_top = needTooltip_bottom - tooltip.outerHeight();
			} else if ((options.verticalAlignment == 'middle') || (options.verticalAlignment == 'center')) {
				var needTooltip_verticalCenter = needTooltip_top + Math.floor(dom.outerHeight() / 2);
				var tooltip_height = tooltip.outerHeight();
				tooltip_top = needTooltip_verticalCenter - Math.floor(tooltip_height / 2);
			} else {
				tooltip_top = needTooltip_top + parseInt(options.verticalAlignment);
			}
		} else if (options.position == 'top') {
			tooltip_top = needTooltip_top - options.speechBubbleHeight - tooltip.outerHeight();
			if (options.horizontalAlignment == 'left') {
				tooltip_left = needTooltip_left;
			} else if (options.horizontalAlignment == 'right') {
				tooltip_left = needTooltip_right - tooltip.outerWidth();
			} else if ((options.horizontalAlignment == 'middle') || (options.horizontalAlignment == 'center')) {
				var needTooltip_horizontalCenter = needTooltip_left + Math.floor(dom.outerWidth() / 2);
				var tooltip_width = tooltip.outerWidth();
				tooltip_left = needTooltip_horizontalCenter - Math.floor(tooltip_width / 2);
			} else {
				tooltip_left = needTooltip_left + parseInt(options.horizontalAlignment);
			}
		} else if (options.position == 'bottom') {
			tooltip_top = needTooltip_bottom + options.speechBubbleHeight;
			if (options.horizontalAlignment == 'left') {
				tooltip_left = needTooltip_left;
			} else if (options.horizontalAlignment == 'right') {
				tooltip_left = needTooltip_right - tooltip.outerWidth();
			} else if ((options.horizontalAlignment == 'middle') || (options.horizontalAlignment == 'center')) {
				var needTooltip_horizontalCenter = needTooltip_left + Math.floor(dom.outerWidth() / 2);
				var tooltip_width = tooltip.outerWidth();
				tooltip_left = needTooltip_horizontalCenter - Math.floor(tooltip_width / 2);
			} else {
				tooltip_left = needTooltip_left + parseInt(options.horizontalAlignment);
			}
		}
		if (tooltip_top < 0) {
			tooltip_top = 0;
		}
		if (tooltip_left < 0) {
			tooltip_left = 0;
		}
		tooltip.css({'position': 'absolute', 'top': tooltip_top, 'left': tooltip_left});
		if (options.showEffect) {
		} else {
			tooltip.show();
		}

		// Display the speech bubble triangle
		if (options.useSpeechBubble) {
			var speech_bubble_id = needTooltipID + '_tooltip_speechbubble';
			var speech_bubble = $('#' + speech_bubble_id);
			if (speech_bubble.length == 0) {
				speech_bubble = $('<div id="' + speech_bubble_id + '"></div>');
			} else {
				speech_bubble.remove();
			}
			speech_bubble.addClass(options.speechBubbleGeneralCSSClass);
			speech_bubble.hide();
			needTooltip_offsetParent.append(speech_bubble);
			var speech_bubble_css = {};
			speech_bubble_css.margin = '0 auto';
			var zindex = tooltip.css('z-index');
			if (zindex == "") {
				zindex = 0;
			}
			zindex = zindex + 1;
			speech_bubble_css['z-index'] = zindex;
			speech_bubble_css['position'] = 'absolute';
			// We first need to determine the pivot point, the base point, and direction for the speech bubble
			// The pivot point is a point on the border of the element that needs tooltip
			// The base point is a point on the border of the tooltip
			var pivotpoint_top = 0;
			var pivotpoint_left = 0;
			var basepoint_top = 0;
			var basepoint_left = 0;
			var center_point_top = 0;
			var center_point_left = 0;
			if (options.position == 'left') {
				pivotpoint_top = needTooltip_top + Math.floor(needTooltip_height / 2);
				pivotpoint_left = needTooltip_left - mandatoryDistance;
				basepoint_top = tooltip_top + Math.floor(tooltip.outerHeight() / 2);
				basepoint_left = tooltip_left + tooltip.outerWidth();
				var speech_bubble_border_width = parseInt(speech_bubble.css('border-left-width'));
				center_point_top = Math.min(basepoint_top,pivotpoint_top) + Math.floor(Math.abs(basepoint_top - pivotpoint_top) / 2) - Math.floor(speech_bubble_border_width);
				center_point_left = basepoint_left;
				speech_bubble_css['top'] = center_point_top + 'px';
				speech_bubble_css['left'] = center_point_left + 'px';
			} else if (options.position == 'right') {
				pivotpoint_top = needTooltip_top + Math.floor(needTooltip_height / 2);
				pivotpoint_left = needTooltip_right + mandatoryDistance;
				basepoint_top = tooltip_top + Math.floor(tooltip.outerHeight() / 2);
				basepoint_left = tooltip_left;
				var speech_bubble_border_width = parseInt(speech_bubble.css('border-right-width'));
				center_point_top = Math.min(basepoint_top,pivotpoint_top) + Math.floor(Math.abs(basepoint_top - pivotpoint_top) / 2) - Math.floor(speech_bubble_border_width);
				center_point_left = basepoint_left - (2 * speech_bubble_border_width);
				speech_bubble_css['top'] = center_point_top + 'px';
				speech_bubble_css['left'] = center_point_left + 'px';
			} else if (options.position == 'top') {
				pivotpoint_top = needTooltip_top;
				pivotpoint_left = needTooltip_left + Math.floor(needTooltip_width / 2);
				basepoint_top = tooltip_top + tooltip.outerHeight();
				basepoint_left = tooltip_left + Math.floor(tooltip.outerWidth() / 2);
				var speech_bubble_border_width = parseInt(speech_bubble.css('border-top-width'));
				center_point_top = basepoint_top;
				center_point_left = basepoint_left - (speech_bubble_border_width);
				speech_bubble_css['top'] = center_point_top + 'px';
				speech_bubble_css['left'] = center_point_left + 'px';
			} else if (options.position == 'bottom') {
				pivotpoint_top = needTooltip_bottom;
				pivotpoint_left = needTooltip_left + Math.floor(needTooltip_width / 2);
				basepoint_top = tooltip_top;
				basepoint_left = tooltip_left + Math.floor(tooltip.outerWidth() / 2);
				var speech_bubble_border_width = parseInt(speech_bubble.css('border-bottom-width'));
				center_point_top = basepoint_top - (2 * speech_bubble_border_width);
				center_point_left = basepoint_left - (speech_bubble_border_width);
				speech_bubble_css['top'] = center_point_top + 'px';
				speech_bubble_css['left'] = center_point_left + 'px';
			}
			speech_bubble.addClass(options.speechBubbleArrowClass);
			speech_bubble.css(speech_bubble_css);
			speech_bubble.show();
		}
	}
	function hide(dom) {
		var needTooltipID = dom.attr('id');
		var options = mergeOptions(needTooltipID);
		var tooltipID = needTooltipID + '_tooltip';
		if (options.hideEffect) {
		} else {
			$('#' + tooltipID).hide();
		}
		var tooltip = $('#' + tooltipID);
		tooltip.removeClass(options.cssClass);
		if (options.useSpeechBubble) {
			var speech_bubble_id = needTooltipID + '_tooltip_speechbubble';
			var speech_bubble = $('#' + speech_bubble_id);
			speech_bubble.remove();
		}
	}
	function init() {
	}

	var methods = {
		'show': show,
		'hide': hide,
		'init': init
	};
	//plugin code will go here...
	$.fn.tooltip = function(method) {
		// Within the body of this method, the function context (this) refers to the wrapped set.
		// But when inline functions are declared within this function, they each have their own function contexts.
		// You must take care when using 'this' under such circumstances to make sure that it is referring to what you think it is.
		// Unless this method is intended to return a specifc value, it should always return the wrapped set.
		if ( methods[method] ) {
			return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' is not defined in jQuery.tooltip' );
		}
	};

	// public functions
	$.fn.tooltip.show = function(e) {
		// This is an event handler, so 'this' refers to the DOM element
		$this = $(this);
		$this.tooltip('show',$this);
	};
	$.fn.tooltip.hide = function(e) {
		$this = $(this);
		$this.tooltip('hide',$this);
	}
	$.fn.tooltip.format = function(txt) {
		// do something
		return '<strong>' + txt + '</strong>';
	};

	// plugin defaults
	$.fn.tooltip.defaults = {
		position: 'right',
		verticalAlignment: 'middle',
		horizontalAlignment: 'center',
		useSpeechBubble: true,
		speechBubbleBase: 6,
		speechBubbleHeight: 10,
		speechBubbleColor: 'green',
		cssClass: 'tooltip-active',
		speechBubbleGeneralCSSClass: 'tooltip_speechbubble'
	};
	$.fn.tooltip.map = {};
})(jQuery);
